今天我們延續昨天的話題, 把 Day 01 的 Hello world 加上酷炫的 Signal & Slot 吧!
這次因為希望能玩到 Signal & Slot 的深入使用, 所以我打算加了兩層 subClass
但是 Day 01 最後的成果看起來真的讓人覺得煩躁, 因為按鈕跑來跑去, 要上下移動按按鈕很麻煩, 所以在這裡我們加一個空白的 QLabel (blank) 卡在原本 Hello 的位置
import sys
from PySide6 import QtCore, QtWidgets
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.isShow = True
self.text = QtWidgets.QLabel("Hello",
alignment=QtCore.Qt.AlignCenter)
self.blank = QtWidgets.QLabel("",
alignment=QtCore.Qt.AlignCenter)
self.button = QtWidgets.QPushButton("Click")
self.button.clicked.connect(self.isShowOrHide)
self.layout = QtWidgets.QVBoxLayout(self)
self.layout.addWidget(self.text)
self.layout.addWidget(self.blank)
self.blank.hide()
self.layout.addWidget(self.button)
def isShowOrHide(self):
if(self.isShow):
self.text.hide()
self.blank.show()
self.isShow = False
else:
self.text.show()
self.blank.hide()
self.isShow = True
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget = MyWidget()
widget.resize(300, 300)
widget.show()
sys.exit(app.exec())
一開始就建好一個要顯示的 QLabel 和卡位用的空白 QLabel, 空白 QLabel 先 hide 藏起來, 之後在函式裡讓兩個 QLabel 交互 show/hide, 讓 click 按鈕能保持在原位
接下來的兩層 subclass 我是用 QLineEdit 下去改寫的, 因為 QLabel 看過了, 來使用看看別的元件吧
成果外觀如圖所示
為了不讓 subWidget1 的文字被 subWidget2 蓋掉, 所以在這裡把 subWidget2 的高度先設定成 100 讓它高一點, 接下來把 subWidget1 的文字使用 setAlignment() 讓文字置於上方中間, 這樣就能看到兩行文字的變化了~
QLineEdit 是個單行的文字輸入框, 但在這裡不需要輸入功能, 所以使用 setDisabled(True) 來將這兩個 QLineEdit 變成不可輸入狀態
在這裡我們用 signal&slot 在每次按鈕被點即時改變 SubWidget1 裡的文字
而在 SubWidget1 改變文字當下, SubWidget2 裡變成點一次按鈕就會加一的數字
import sys
from PySide6 import QtCore, QtWidgets
class SubWidget2(QtWidgets.QLineEdit):
signal_addNum = QtCore.Signal()
def __init__(self):
super(SubWidget2, self).__init__()
self.numbers = 0
@QtCore.Slot()
def addNumText(self):
self.numbers = self.numbers + 1
self.setText(str(self.numbers))
class SubWidget1(QtWidgets.QLineEdit):
signal_showText = QtCore.Signal(str)
def __init__(self):
super(SubWidget1, self).__init__()
self.setFixedHeight(100)
self.subWidget2 = SubWidget2()
self.subWidget2.setText("SubWidget2")
self.subWidget2.setDisabled(True)
self.subWidget2.setAlignment(QtCore.Qt.AlignCenter)
self.subWidget2.signal_addNum.connect(self.subWidget2.addNumText)
self.layout = QtWidgets.QHBoxLayout(self)
self.layout.addWidget(self.subWidget2)
@QtCore.Slot(str)
def setTextAB(self, txt : str):
self.setText(txt)
self.subWidget2.signal_addNum.emit()
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.isShow = True
self.subWidget1 = SubWidget1()
self.subWidget1.setText("SubWidget1")
self.subWidget1.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignHCenter)
self.subWidget1.setDisabled(True)
self.subWidget1.signal_showText.connect(self.subWidget1.setTextAB)
self.text = QtWidgets.QLabel("Hello",
alignment=QtCore.Qt.AlignCenter)
self.blank = QtWidgets.QLabel("",
alignment=QtCore.Qt.AlignCenter)
self.button = QtWidgets.QPushButton("Click")
self.button.clicked.connect(self.isShowOrHide)
self.layout = QtWidgets.QVBoxLayout(self)
self.layout.addWidget(self.text)
self.layout.addWidget(self.blank)
self.blank.hide()
self.layout.addWidget(self.subWidget1)
self.layout.addWidget(self.button)
def isShowOrHide(self):
if(self.isShow):
self.text.hide()
self.blank.show()
self.isShow = False
self.subWidget1.signal_showText.emit("A")
else:
self.text.show()
self.blank.hide()
self.isShow = True
self.subWidget1.signal_showText.emit("B")
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget = MyWidget()
widget.resize(300, 300)
widget.show()
sys.exit(app.exec())
成果
雖然以這個程式來看 signal&slot 好像也就普普, 但是在大型的專案裡, 要在最上層把訊號傳給某個下層, 尤其是當 class 在不同的 .py 擋, 但訊號要互傳的話, 這個機制就會很方便。